package com.iplant.ams.serviceImpl;

import com.iplant.ams.service.DFBService;
import com.iplant.ams.service.basicenum.exc.EXCUnusualTypes;
import com.iplant.ams.service.po.dms.DMSDeviceType;
import com.iplant.ams.service.po.dms.fault.DMSFaultBase;
import com.iplant.ams.service.po.dms.fault.DMSFaultBaseBPM;
import com.iplant.ams.service.po.dms.maintenance.DMSMaintenanceItemRecord;
import com.iplant.ams.serviceImpl.dao.dms.fault.DMSFaultBaseBPMDAO;
import com.iplant.ams.serviceImpl.dao.dms.maintenance.DMSMaintenanceItemRecordDAO;
import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.ServiceResult;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.po.excel.ExcelData;
import com.iplant.base.po.excel.ExcelSheetData;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.orm.ORMUtils;
import com.iplant.base.utils.sql.orm.PoService;
import com.iplant.basic.service.basicenum.bfc.BFCMessageStatus;
import com.iplant.basic.service.basicenum.bfc.BFCMessageType;
import com.iplant.basic.service.basicenum.bpm.BPMEventModule;
import com.iplant.basic.service.basicenum.bpm.BPMTaskStatus;
import com.iplant.basic.service.basicenum.bpm.TaskQueryType;
import com.iplant.basic.service.po.bfc.BFCMessage;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.basic.service.po.bms.BMSRoleItem;
import com.iplant.basic.serviceImpl.BFCServiceImpl;
import com.iplant.basic.serviceImpl.BMSServiceImpl;
import com.iplant.basic.utils.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@Service
public class DFBServiceImpl implements DFBService {

    //region 构造函数
    public DFBServiceImpl() {
        Constants.BPMServiceMap.put(BPMEventModule.FaultBaseAudit, this);
    }
    //endregion

    //region POService
    PoService<DMSFaultBase> mDMSFaultBaseService = ORMUtils.GetPoService(DMSFaultBase.class);
    PoService<DMSDeviceType> mDMSDeviceTypeService = ORMUtils.GetPoService(DMSDeviceType.class);
    //endregion

    //region 单实例

    private static DFBService Instance = null;

    public static DFBService getInstance() {
        if (Instance == null)
            Instance = new DFBServiceImpl();

        return Instance;
    }


    //endregion

    //region 流程
    @Override
    public ServiceResult<DMSFaultBaseBPM> BPM_QueryDefaultTask(BMSEmployee wLoginUser,
                                                               int wTaskID, int wEventID) {
        ServiceResult<DMSFaultBaseBPM> wResult = new ServiceResult<>();
        wResult.Result = new DMSFaultBaseBPM();
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);


            Map<String, Object> wParams = new HashMap<String, Object>();
            wParams.put("UpFlowID", wLoginUser.ID);
            wParams.put("Status", "0");

            DMSFaultBaseBPM wBPMTaskBase = DMSFaultBaseBPMDAO.getInstance().SelectPO(wLoginUser,
                    wParams, wErrorCode);
            if (wBPMTaskBase != null && wBPMTaskBase.ID > 0) {
                wBPMTaskBase.FlowType = wEventID;
                wBPMTaskBase.UpFlowID = wLoginUser.ID;
                wBPMTaskBase.UpFlowName = wLoginUser.Name;

                wResult.Result = wBPMTaskBase;
            }

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());

        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error(e.toString());
        }
        return wResult;
    }


    @Override
    public ServiceResult<DMSFaultBaseBPM> BPM_CreateTask(BMSEmployee wLoginUser,
                                                         BPMEventModule wEventID) {
        ServiceResult<DMSFaultBaseBPM> wResult = new ServiceResult<>();
        wResult.Result = new DMSFaultBaseBPM();
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            DMSFaultBaseBPM wPo = new DMSFaultBaseBPM();
            wPo.setUserInfo(wLoginUser);
            wPo.ID = 0;
            wPo.FlowType = wEventID.getValue();
            wPo.UpFlowID = wLoginUser.ID;
            wPo.UpFlowName = wLoginUser.Name;
            wPo.Status = 0;
            wPo.StatusText = "";
            wPo.CreateTime = Calendar.getInstance();
            wPo.EditTime = Calendar.getInstance();


            DMSFaultBaseBPMDAO.getInstance().UpdatePo(wLoginUser, wPo, wErrorCode);

            wResult.Result = wPo;

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error(e.toString());
        }
        return wResult;
    }

    @Override
    public ServiceResult<DMSFaultBaseBPM> BPM_SubmitTask(BMSEmployee wLoginUser,
                                                         DMSFaultBaseBPM wData) {
        ServiceResult<DMSFaultBaseBPM> wResult = new ServiceResult<>();
        wResult.Result = wData;
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            if (wData.Status == BPMTaskStatus.Confirm.getValue()) {
                wData.StatusText = "已完成";
                if (StringUtils.isNotEmpty(wData.NewFaultDescription)) {
                    //①推送待办消息给管理员
                    List<BFCMessage> wBFCMessageList = new ArrayList<>();
                    BFCMessage wMessage = null;
                    SimpleDateFormat wSDF = new SimpleDateFormat("yyyyMMdd");
                    int wShiftID = Integer.parseInt(wSDF.format(Calendar.getInstance().getTime()));
                    List<BMSRoleItem> wBMSRoleItemList =
                            BMSServiceImpl.getInstance().BMS_QueryUserListByRoleID(wLoginUser, 12).Result;
                    for (BMSRoleItem wBMSRoleItem : wBMSRoleItemList) {
                        // 发送任务消息到人员
                        wMessage = new BFCMessage();
                        wMessage.Active = 0;
                        wMessage.CompanyID = 0;
                        wMessage.CreateTime = Calendar.getInstance();
                        wMessage.EditTime = Calendar.getInstance();
                        wMessage.ID = 0;
                        wMessage.MessageID = wData.ID;
                        wMessage.Title = wData.Code;
                        wMessage.MessageText = StringUtils.Format("【{0}】 {1}创建故障知识库维护消息，请及时处理。",
                                BPMEventModule.FaultBaseRepairAudit.getLabel(), wLoginUser.Name);
                        wMessage.ModuleID = BPMEventModule.FaultBaseRepairAudit.getValue();
                        wMessage.ResponsorID = wBMSRoleItem.FunctionID;
                        wMessage.ShiftID = wShiftID;
                        wMessage.StationID = 0;
                        wMessage.Type = BFCMessageType.Task.getValue();
                        wBFCMessageList.add(wMessage);
                    }

                    BFCServiceImpl.getInstance().BFC_UpdateMessageList(wLoginUser, wBFCMessageList);
                }

                DMSMaintenanceItemRecord wMaintenanceItemRecord = new DMSMaintenanceItemRecord(wData);

                DMSMaintenanceItemRecordDAO.getInstance().UpdatePo(wLoginUser, wMaintenanceItemRecord
                        , wErrorCode);
            }

            wData.setUserInfo(wLoginUser);
            wData.EditTime = Calendar.getInstance();
            ORMUtils.GetPoService(DMSFaultBaseBPM.class).UpdatePo(wLoginUser, wData, wErrorCode);

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error(e.toString());
        }
        return wResult;
    }

    @Override
    public ServiceResult<DMSFaultBaseBPM> BPM_GetTask(BMSEmployee wLoginUser, int wID) {
        ServiceResult<DMSFaultBaseBPM> wResult = new ServiceResult<>();
        OutResult<Integer> wErrorCode = new OutResult<>(0);
        wResult.Result = DMSFaultBaseBPMDAO.getInstance().SelectPO(wLoginUser, wID, "", wErrorCode);
        wResult.AddFaultCode(wErrorCode);
        return wResult;
    }

    @Override
    public Class<DMSFaultBaseBPM> GetTClass() {
        return DMSFaultBaseBPM.class;
    }


    @Override
    public ServiceResult<List<DMSFaultBaseBPM>> BPM_QueryEmployeeAllWeb(BMSEmployee wLoginUser, Map<String,
            Object> wParams, Pagination wPagination) {
        ServiceResult<List<DMSFaultBaseBPM>> wResult = new ServiceResult<>();
        wResult.Result = new ArrayList<>();
        OutResult<Integer> wErrorCode = new OutResult<>(0);
        try {
            int wStatus = StringUtils.parseInt(wParams.get("Status"));
            switch (wStatus) {
                case 0://待办
                    wParams.put("Status", "2,3,4,5,6,7");
                    wResult.Result = DMSFaultBaseBPMDAO.getInstance().SelectPOList(wLoginUser, wParams, wPagination,
                            wErrorCode);
                    break;
                case 1://已办
                    wParams.put("Status", "20,21,22");
                    wResult.Result = DMSFaultBaseBPMDAO.getInstance().SelectPOList(wLoginUser, wParams, wPagination,
                            wErrorCode);
                    break;
                default://全部
                    wParams.put("Status", "2,3,4,5,6,7,20,21,22");
                    wResult.Result = DMSFaultBaseBPMDAO.getInstance().SelectPOList(wLoginUser, wParams, wPagination,
                            wErrorCode);
                    break;
            }

            if (wResult.Result.size() <= 0 || wStatus == 1) {
                return wResult;
            }

            // 待办数据处理
            List<DMSFaultBaseBPM> wBaseList =
                    DMSFaultBaseBPMDAO.getInstance().BFC_GetUndoTaskList(wLoginUser,
                            wLoginUser.ID, StringUtils.parseListArgs(BPMEventModule.FaultBaseAudit.getValue())
                            , wParams, Pagination.getNewMaxSize(), wErrorCode);
            if (wBaseList == null || wBaseList.size() <= 0) {
                return wResult;
            }
            for (DMSFaultBaseBPM wTaskBase : wBaseList) {
                wTaskBase.TagTypes = TaskQueryType.ToHandle.getValue();
                for (int i = 0; i < wResult.Result.size(); i++) {
                    if (wResult.Result.get(i).ID == wTaskBase.ID)
                        wResult.Result.set(i, wTaskBase);
                }
            }

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error(e.toString());
        }
        return wResult;
    }


    //endregion

    @Override
    public ServiceResult<Integer> DMS_SubmitFaultBase(BMSEmployee wLoginUser, DMSFaultBase wDMSFaultBase, int wTaskID) {
        ServiceResult<Integer> wResult = new ServiceResult<>(0);
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            wDMSFaultBase.Active = 1;
            int wAffectRows = mDMSFaultBaseService.UpdatePo(wLoginUser, wDMSFaultBase, wErrorCode);
            if (wAffectRows <= 0) {
                wResult.FaultCode += "更新故障知识库失败，请联系系统管理员!";
            }

            //关闭消息
            BFCServiceImpl.getInstance().BFC_HandleTaskMessage(wLoginUser, wLoginUser.ID,
                    new ArrayList<>(Collections.singletonList(wTaskID)), BPMEventModule.FaultBaseRepairAudit.getValue(),
                    0, BFCMessageStatus.Finished.getValue(), 1, wDMSFaultBase.CreateTime, Calendar.getInstance());

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error(e.toString());
        }
        return wResult;
    }

    //region 知识库导入
    @Override
    public ServiceResult<Integer> DMS_FaultBaseImport(BMSEmployee wLoginUser, ExcelData wExcelData) {
        ServiceResult<Integer> wResult = new ServiceResult<>(0);
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            if (wExcelData == null || wExcelData.sheetData == null || wExcelData.sheetData.size() == 0) {
                wResult.FaultCode += "Excel格式错误!";
                return wResult;
            }

            Map<String, Object> wParams = new HashMap<String, Object>();

            ExcelSheetData wExcelSheetData = wExcelData.sheetData.get(0);


            DMSDeviceType wDeviceType;
            List<DMSDeviceType> wDeviceTypeList = new ArrayList<>();
            DMSFaultBase wDMSFaultBase;
            List<DMSFaultBase> wDMSFaultBaseList = new ArrayList<>();
            int wTypeID = 0;
            int wExcTypeID = 0;
            for (int i = 0; i < wExcelSheetData.lineData.size(); i++) {
                if (i == 0) {
                    continue;
                }

                int wIndex = 0;

                String wDescription = wExcelSheetData.lineData.get(i).colData.get(wIndex++);
                if (StringUtils.isEmpty(wDescription)) {
                    continue;
                }
                String wHandleWay = wExcelSheetData.lineData.get(i).colData.get(wIndex++);
                if (StringUtils.isEmpty(wHandleWay)) {
                    wResult.FaultCode += StringUtils.Format("第【{0}】行数据有误，处置办法不能为空!", i + 1);
                    return wResult;
                }
                //设备类型
                String wDeviceTypeName = wExcelSheetData.lineData.get(i).colData.get(wIndex++);
                //异常类型
                String wExcTypeName = wExcelSheetData.lineData.get(i).colData.get(wIndex++);

                //设备类型
                if (wDeviceTypeList.stream().anyMatch(p -> p.Name.equals(wDeviceTypeName))) {
                    wDeviceType =
                            wDeviceTypeList.stream().filter(p -> p.Name.equals(wDeviceTypeName)).findFirst().get();
                } else {
                    wParams.clear();
                    wParams.put("NameEQ", wDeviceTypeName);
                    wDeviceType = mDMSDeviceTypeService.SelectPO(wLoginUser, wParams,
                            wErrorCode);
                    if (wDeviceType == null || wDeviceType.ID <= 0) {
                        wResult.FaultCode += StringUtils.Format("设备类型【{0}】不存在!", wDeviceTypeName);
                        return wResult;
                    }
                    wDeviceTypeList.add(wDeviceType);
                }
                switch (wExcTypeName) {
                    case "设备":
                        wExcTypeID = 1;
                        break;
                    case "质量":
                        wExcTypeID = 2;
                        break;
                    case "工艺":
                        wExcTypeID = 3;
                        break;
                    case "物料":
                        wExcTypeID = 4;
                        break;
                    case "其它":
                        wExcTypeID = 5;
                        break;
                    default:
                        wExcTypeID = 0;
                        break;
                }

                wDMSFaultBase = new DMSFaultBase();
                wDMSFaultBase.HandleWay = wHandleWay;
                wDMSFaultBase.FileUrl = "";
                wDMSFaultBase.DeviceTypeID = wDeviceType.ID;
                wDMSFaultBase.Code = "";
                wDMSFaultBase.Description = wDescription;
                wDMSFaultBase.Type = 2;
                wDMSFaultBase.ExcType = wExcTypeID;
                wDMSFaultBase.CreateTime = Calendar.getInstance();
                wDMSFaultBase.setUserInfo(wLoginUser);
                wDMSFaultBase.Active = 1;

                //知识库编码维护
                wParams.clear();
                wParams.put("DescriptionEQ", wDescription);
                DMSFaultBase dmsFaultBase = mDMSFaultBaseService.SelectPO(wLoginUser, wParams,
                        wErrorCode);
                if (dmsFaultBase != null && dmsFaultBase.ID > 0) {
                    wDMSFaultBase.Code = dmsFaultBase.Code;
                } else {
                    wDMSFaultBase.Code = GetNewCodeByExcType(wLoginUser, wDMSFaultBase.ExcType, wErrorCode);
                }

                wDMSFaultBaseList.add(wDMSFaultBase);
            }

            //调用知识库保存接口
            mDMSFaultBaseService.UpdatePoList(wLoginUser, wDMSFaultBaseList, wErrorCode);
            if (StringUtils.isNotEmpty(wResult.FaultCode)) {
                return wResult;
            }

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error(e.toString());
        }
        return wResult;
    }

    //endregion

    @Override
    public ServiceResult<Integer> DMS_UpdateFaultBase(BMSEmployee wLoginUser, DMSFaultBase wDMSFaultBase) {
        ServiceResult<Integer> wResult = new ServiceResult<>(0);
        try {
            OutResult<Integer> wErrorCode = new OutResult<>(0);

            if (wDMSFaultBase.ID <= 0) {
                //重新计算知识库编码
                wDMSFaultBase.Code = GetNewCodeByExcType(wLoginUser, wDMSFaultBase.ExcType, wErrorCode);
            }
            wDMSFaultBase.setUserInfo(wLoginUser);
            mDMSFaultBaseService.UpdatePo(wLoginUser, wDMSFaultBase, wErrorCode);
            wResult.Result = wDMSFaultBase.ID;

            wResult.setFaultCode(ExceptionTypes.getEnumType(wErrorCode.Result).getLabel());
        } catch (Exception e) {
            wResult.FaultCode += e.toString();
            log.error(e.toString());
        }
        return wResult;
    }

    /**
     * 根据异常类型计算最新的编码
     */
    private String GetNewCodeByExcType(BMSEmployee wLoginUser, int excType, OutResult<Integer> wErrorCode) {
        String wResult = "";
        try {
            Map<String, Object> wParams = new HashMap<String, Object>();
            wParams.put("ExcType", excType);

            String excCode = EXCUnusualTypes.getEnumType(excType).getExcCode();

            Pagination wPagination = Pagination.Create(1, 1, DMSFaultBase.class);
            wPagination.setSort("ID DESC");
            List<DMSFaultBase> dmsFaultBases = mDMSFaultBaseService.SelectPOList(wLoginUser, wParams,
                    wPagination,
                    wErrorCode);
            if (dmsFaultBases.size() > 0 && dmsFaultBases.get(0).Code.contains(excCode)) {
                DMSFaultBase dmsFaultBase = dmsFaultBases.get(0);
                int wNumber = StringUtils.parseInt(dmsFaultBase.Code.substring(4));
                //Number加一，转为4位流水号
                wResult = StringUtils.Format("{0}{1}", excCode, String.format("%04d", wNumber + 1));
            } else {
                wResult = StringUtils.Format("{0}{1}", excCode, String.format("%04d", 1));
            }
        } catch (Exception ex) {
            log.error("GetNewCodeByExcType", ex);
        }
        return wResult;
    }
}
